﻿#pragma once

#include <GraphicsPinkItem.h>
#include <GraphicsUtil.h>
#include <GraphicsBaseItemData.h>
#include <GraphicsLineItem.h>
#include <GraphicsBaseOperation.h>
#include <GraphicsWatermarkItem.h>

class GraphicsScene;

class GraphicsBaseItem : public QGraphicsObject
{
private:
	Q_OBJECT
public:
	GraphicsBaseItem(GraphicsItemType baseItemType, GraphicsScene* scene, GraphicsBaseItem* parent = nullptr);

	// 拉伸图元
	void stretchGraphics(GraphicsPinkItemType type, const QPointF& delta);

	// 旋转图元
	void rotateGraphics(const QPointF& mouseScenePoint);

	// 缩放图元
	virtual void scaleGraphics(GraphicsPinkItemType /*type*/, const QPointF& /*delta*/) {};

	// 添加子图元
	void addChild(GraphicsBaseItem* child);

	// 控制点开始
	virtual void operationStart(GraphicsPinkItemType type, const QPointF& mousePoint);

	// 控制点正在控制
	virtual void operationDoing(GraphicsPinkItemType type, const QPointF& mousePoint);

	// 控制点控制完成
	virtual void operationDone(GraphicsPinkItemType type, const QPointF& mousePoint);

	// 更新图元
	void refresh();

	// 获取点击时刻图元信息
	GraphicsItemInfo getPressedItemInfo()const { return m_data.getPressItemInfo(); }

	GraphicsBaseItemData& getItemData() { return m_data; }

	// 设置吸附线可见性
	void setAbsorptionLineVisable(GraphicsLineType lineType, bool isVisable);

	// 更新吸附线的位置
	void updateAbsorptionLinePos();

	// 获取上下文信息(带缩放系数)
	QRectF getContextRect()const { return m_data.getContext().rect; }

	// 获取上下文信息
	GraphicsItemInfo getContext()const { return m_data.getContext(); }

	// 获取场景
	GraphicsScene* getScene() { return m_scene; }

	// 移到父控件的中心位置
	void moveToParentCenter();

	// 添加操作类
	void addOperation(GraphicsBaseOperation* operation);

	//  获取操作类
	template<typename T>
	T* getOperation(GraphicsOperationType operationType) {
		T* operation = dynamic_cast<T*>(m_operationMap[operationType]);
		assert(operation != nullptr);
		return operation;
	}

	void addPinkItem(GraphicsPinkItem* pinkItem);

	// 添加吸附线
	void addAbsorptionLine(GraphicsLineItem* lineItem);

	// 创建水印
	void createWatermark();

	// 是否显示水印
	void setWatermarkVisable(bool visable);
public slots:
	void onUpdateWatermarkGeometry();

	void onPosChanged(const QPointF& newPos);

	void onSizeChanged();

	void onUpdatePinkItemPosition();

	void onRotateAngleChanged();
signals:
	// 尺寸发生改变的信号
	void sigSizeChanged(const QSize& size);

	// 到达最大边界
	void sigReachMaxSize();
protected:
	QMap<GraphicsBaseItem*, GraphicsItemInfo> getChildPressedContextMap()const;

	// 设置控制点是否可见
	void setPinksItemVisabled(bool isVisabled);

	// 设置图元移动
	void enableMove(bool isCanMoveable);

	// 设置以图元为中心
	void setOriginOnCenter();

	// 初始化图元
	virtual void initGraphics() = 0;

	// 以边角点进行缩放图元
	void stretchGraphicsOnCorner(GraphicsPinkItemType type, const QPointF& delta);

	// 以边角点进行缩放图元(等比缩放)
	void stretchGraphicsOnCornerKeepRatio(GraphicsPinkItemType type, const QPointF& delta);

	// 以中心点进行缩放图元
	void scaleGraphicsOnCenter(GraphicsPinkItemType type, const QPointF& delta);
protected:
	// boundingRect函数功能，是将图形项的外部边界定义为一个矩形。
	// 所有的绘图操作都必须限制在图形的边界矩形中，
	// QGraphicsView需要使用这个边界来确定重绘的区域。
	// 在这个区域内，可以响应hover,按下等鼠标事件
	virtual QRectF boundingRect() const override;

	// 进行碰撞检测
	virtual QPainterPath shape() const override;

	virtual void hoverEnterEvent(QGraphicsSceneHoverEvent* event)override;

	virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event)override;

	virtual QVariant itemChange(GraphicsItemChange change, const QVariant& value) override;

	virtual void mousePressEvent(QGraphicsSceneMouseEvent* event)override;

	virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event)override;

	virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event)override;
private:
	void setPinksItemOpacity(qreal opacity);

	void setBorderColor(GraphicsBorderColor color);
protected:
	// 场景
	GraphicsScene* m_scene = nullptr;
	GraphicsBaseItemData m_data;
	// 操作类
	QMap<GraphicsOperationType, GraphicsBaseOperation*> m_operationMap;
private:
	// 控制点
	QMap<GraphicsPinkItemType, GraphicsPinkItem*> m_pinkItemMap;
	// 吸附线
	QMap<GraphicsLineType, GraphicsLineItem*> m_absorptionLineItemMap;
	// 水印
	GraphicsWatermarkItem* m_watermark = nullptr;
};
